package com.blue.spring.redis;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;

public class RedisCache
{
	private static Logger logger = LoggerFactory.getLogger(RedisCache.class);

	private static final int EXPIRE = 600; // redis 锁过期时间，秒
	private static final int WAIT_FOR_LOCK = 100; // 检查锁间隔时间，毫秒
	private static final int DEFAULT_TIMEOUNT = 5000; // 默认锁时间，毫秒

	@Autowired(required = false)
	@Qualifier("redisTemplate")
	protected RedisTemplate<String, Object> redisTemplate;

	public RedisCache()
	{
	}

	/**
	 * 设置缓存
	 * 
	 * @param <T> 类型参数
	 * @param key 键
	 * @param obj 值
	 */
	public void set(String key, Object obj)
	{
		this.set(key, obj, 1, TimeUnit.HOURS);
	}

	/**
	 * 设置缓存
	 * 
	 * @param key 键
	 * @param obj 值
	 * @param n 数量
	 * @param unit 时间单位
	 */
	public void set(String key, Object obj, long n, TimeUnit unit)
	{
		if (redisTemplate == null || key == null || obj == null)
			return;

		redisTemplate.boundValueOps(key).set(obj, n, unit);
		logger.debug("更新缓存 key={}", key);
	}

	/**
	 * 获取缓存
	 * 
	 * @param <T> 类型参数
	 * @param key 键
	 * @return 缓存对象
	 */
	@SuppressWarnings("unchecked")
	public <T> T get(String key)
	{
		if (redisTemplate == null || key == null)
			return null;

		T obj = (T)redisTemplate.boundValueOps(key).get();
		logger.debug("命中缓存 key={}，{}", key, obj != null);
		return obj;
	}
	
	/**
	 * 获取对象过期时间，单位：秒
	 * 
	 * @param key 键
	 * @return 获取对象还有多少秒过期，-1表示不存在
	 */
	public int expire(String key)
	{
		if (redisTemplate == null || key == null)
			return -1;
		
		Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
		return expire == null ? -1 : expire.intValue();
	}

	/**
	 * 删除缓存
	 * 
	 * @param key 键
	 */
	public void delete(String key)
	{
		if (redisTemplate == null || key == null)
			return;

		redisTemplate.delete(key);
	}

	/**
	 * 比较是否相等
	 * 
	 * @param key 键
	 * @param obj 值
	 * @return
	 */
	public boolean equals(String key, Object obj)
	{
		if (redisTemplate == null || key == null || obj == null)
			return false;

		Object o = redisTemplate.boundValueOps(key).get();
		return obj.equals(o);
	}

	/**
	 * 对key加锁
	 * 
	 * @param key
	 * @param timeout 超时，单位毫秒
	 * @return
	 */
	public boolean lock(String key, int timeout)
	{
		String lockKey = key + "~lock";

		long now = System.currentTimeMillis();
		while ((System.currentTimeMillis() - now) < timeout)
		{
			if (redisTemplate.boundValueOps(lockKey).setIfAbsent(lockKey).booleanValue())
			{
				redisTemplate.expire(lockKey, EXPIRE, TimeUnit.SECONDS);
				return true;
			}
			try
			{
				Thread.sleep(WAIT_FOR_LOCK);
			}
			catch (InterruptedException ex)
			{
				// 忽略
			}
		}
		return false;
	}

	/**
	 * 对key加锁，默认超时5秒
	 * 
	 * @param key
	 * @return
	 */
	public boolean lock(String key)
	{
		return this.lock(key, DEFAULT_TIMEOUNT);
	}

	/**
	 * 对key解锁
	 * 
	 * @param key
	 */
	public void unlock(String key)
	{
		String lockKey = key + "~lock";

		redisTemplate.delete(lockKey);
	}

	/**
	 * 判断key是否加锁
	 * 
	 * @param key
	 * @return true为加锁，false为解锁
	 */
	public boolean isLock(String key)
	{
		String lockKey = key + "~lock";
		return redisTemplate.hasKey(lockKey);
	}

}
